package com.efeichong.common.config;

import com.efeichong.annotation.RepeatSubmit;
import com.efeichong.common.exception.CustomException;
import com.efeichong.common.utils.LockUtils;
import com.efeichong.common.utils.NetworkUtil;
import com.efeichong.util.EntityUtils;
import com.google.common.base.Charsets;
import lombok.SneakyThrows;
import org.apache.commons.codec.digest.DigestUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.stream.Collectors;

/**
 * @author lxk
 * @date 2022/8/21
 * @description 防止重复提交切面处理
 */
@Component
@Aspect
public class RepeatSubmitAspect {

    @Autowired
    StringRedisTemplate redisTemplate;
    @Value("${token.header}")
    private String tokenHeader;

    @SneakyThrows
    @Around("execution(* com..controller..*.*(..)) && @annotation(rs)")
    public Object repeatSubmitCheck(ProceedingJoinPoint joinPoint, RepeatSubmit rs) {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        StringBuilder keyBuilder = new StringBuilder();

        String queryString = decode(request.getQueryString());
        String url = request.getMethod() + ":" + request.getRequestURI() + "?" + queryString;
        keyBuilder.append(url);

        if (request.getContentLength() != -1) {
            keyBuilder.append(request.getReader().lines().collect(Collectors.joining()));
        }
        String token = request.getHeader(tokenHeader);
        if (EntityUtils.isNotEmpty(token)) {
            keyBuilder.append(token);
        }

        String ipAddress = NetworkUtil.getIpAddress(request);
        keyBuilder.append(ipAddress);

        String key = DigestUtils.md5Hex(keyBuilder.toString()) + keyBuilder.length();
        boolean lock = LockUtils.lock(key);
        try {
            return joinPoint.proceed();
        } finally {
            LockUtils.unlock(key);
            if (!lock) {
                throw new CustomException("请勿重复提交");
            }
        }
    }

    @SneakyThrows
    private String decode(String queryString) {
        if (queryString == null) {
            return "";
        } else {
            return URLDecoder.decode(queryString, Charsets.UTF_8.name());
        }
    }
}
